package com.hzit.loan.pay.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.hzit.loan.pay.commonApi.enums.NotifyResultEnum;
import com.hzit.loan.pay.commonApi.enums.PayStatusEnum;
import com.hzit.loan.pay.commonApi.resp.PayNotifyData;
import com.hzit.loan.pay.commonApi.utils.PayDigestUtil;
import com.hzit.loan.pay.config.MqConfig;
import com.hzit.loan.pay.config.PayConfig;
import com.hzit.loan.pay.mapper.MchInfoMapper;
import com.hzit.loan.pay.mapper.NotifyResultMapper;
import com.hzit.loan.pay.mapper.PaySerialMapper;
import com.hzit.loan.pay.model.MchInfo;
import com.hzit.loan.pay.model.PaySerial;
import com.hzit.loan.pay.service.INotifyResultService;
import com.hzit.loan.pay.service.INotifyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Schedules;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * 支付异步回调相关业务接口实现类
 */
@Service

//@Scheduled, xxl-job 分布式任务调度平台
public class NotifyServiceImpl implements INotifyService {


    @Autowired
    private PaySerialMapper paySerialMapper;

    @Autowired
    private MchInfoMapper mchInfoMapper;

    @Autowired
    private INotifyResultService notifyResultService ;

    @Autowired
    private PayConfig payConfig;

    private static final String TRADE_SUCCESS = "TRADE_SUCCESS";

    private static final String TRADE_FINISHED = "TRADE_FINISHED";

    private static final String TRADE_CLOSED = "TRADE_CLOSED";


    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RestTemplate restTemplate;

    private Logger logger = LoggerFactory.getLogger(NotifyServiceImpl.class);

    private static final SimpleDateFormat df = new SimpleDateFormat("yyyyMMddhhmmss");

    /**
     * 更新流水
     * @param params
     * @return
     */
    @Override
    public String doNotify(Map<String, String> params) {


//      3. 商户需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号
        String paySerialNo = params.get("out_trade_no");

        PaySerial paySerial = paySerialMapper.queryByPaySerialNo(paySerialNo);

        if (ObjectUtils.isEmpty(paySerial)){
            logger.info("支付宝异步回调返回流水号：{}没有在流水表中找到对应的支付流水",paySerialNo);
            return "fail";
        }

//      4.判断 total_amount 是否确实为该订单的实际金额（即商户订单创建时的金额）；

        String totalAmount = params.get("total_amount");
        if(StringUtils.isEmpty(totalAmount)){
            logger.info("支付宝异步回调返回流水号：{}对应的支付金额为空",paySerialNo);
            return "fail";
        }

        if(!totalAmount.equals(paySerial.getMchOrderAmount().toString())){
            logger.info("支付宝异步回调返回流水号：{}与流水表中金额不匹配",paySerialNo);
            return "fail";
        }

//      5.校验通知中的 seller_id（或者 seller_email) 是否为 out_trade_no 这笔单据的对应的操作方（有的时候，一个商户可能有多个 seller_id/seller_email）；

        String sellerEmail = params.get("seller_email");
        if (!payConfig.getAlipaySellerEmail().equals(sellerEmail)){
            logger.info("支付宝异步回调返回流水号：{}seller_email不匹配",paySerialNo);
            return "fail";
        }


//      6.验证 app_id 是否为该商户本身
        String appId = params.get("app_id");

        if (!payConfig.getAlipayAppId().equals(appId)){
            logger.info("支付宝异步回调返回流水号：{}appId不匹配",paySerialNo);
            return "fail";
        }

//      7.更新支付流水表状态，TRADE_SUCCESS 或 TRADE_FINISHED  更新成功
        String tradeStatus = params.get("trade_status");

        if (TRADE_SUCCESS.equals(tradeStatus) || TRADE_FINISHED.equals(tradeStatus)){
            //更新成功
            PaySerial record = new PaySerial();

            String bankRespNo = params.get("trade_no");

            String gmtPaymentStr = params.get("gmt_payment");

            try {
                Date gmtPayment = df.parse(gmtPaymentStr);
                record.setPaySuccessTime(gmtPayment);
            } catch (ParseException e) {
                logger.error("ParseException",e);
            }

            record.setId(paySerial.getId());
            record.setStatus(PayStatusEnum.SUCCESS.getCode().toString());
            record.setUpdateTime(new Date());
            record.setBankRespMsg(PayStatusEnum.SUCCESS.getDesc());
            record.setBankRespNo(bankRespNo);
            paySerialMapper.updateByPrimaryKeySelective(record);

            sendNotifyToBizSystem(record);

            return "success";

        }else if (TRADE_CLOSED.equals(tradeStatus)){
            //更新失败

            PaySerial record = new PaySerial();
            record.setId(paySerial.getId());
            record.setStatus(PayStatusEnum.FAIL.getCode().toString());
            record.setBankRespMsg(PayStatusEnum.FAIL.getDesc());
            record.setUpdateTime(new Date());
            String bankRespNo = params.get("trade_no");
            record.setBankRespNo(bankRespNo);
            paySerialMapper.updateByPrimaryKeySelective(record);

            sendNotifyToBizSystem(record);
            return "success";
        }else{

            return "fail";
        }



//      8.通知业务系统更新订单状态

    }

    /**
     * 发送通知给业务系统
     * @param paySerial
     */
    private void sendNotifyToBizSystem(PaySerial paySerial){

        PayNotifyData object = new PayNotifyData();
        object.setMchOrderId(paySerial.getMchOrderNo());
        object.setTradeStatus(paySerial.getStatus());
        object.setFinishedTime(paySerial.getPaySuccessTime());
        object.setPayChannel(paySerial.getPayChannel());
        object.setPayWay(paySerial.getPayWay());
        MchInfo mchInfo =  mchInfoMapper.queryMchInfoByMchId(paySerial.getMchId());
        String sign = null;
        try {
            sign = PayDigestUtil.getSign(object,mchInfo.getRespKey());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        object.setSign(sign);


        //第一次发送请求
        String result = restTemplate.postForObject("",object,String.class);

        logger.info("result = " + result);

        if(!"success".equals(result)){
            //TODO 确保消息返回给了业务系统
            //把消息丢到队列中5m（延时队列 死信队列+ ttl）
            rabbitTemplate.convertAndSend(MqConfig.PAY_NOTIFY_EXCHANGE_NAME,"",object);
            notifyResultService.updateNotifyResult(paySerial.getPaySerialNo(),NotifyResultEnum.NOTIFY_FAIL);
        }else{
            notifyResultService.updateNotifyResult(paySerial.getPaySerialNo(), NotifyResultEnum.NOTIFY_SUCCESS);

        }



    }

}
